package cn.iocoder.yudao.module.asasc.job;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils;
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
import cn.iocoder.yudao.module.asasc.config.AsaConst;
import cn.iocoder.yudao.module.asasc.controller.admin.campaign.vo.CampaignDataSaveReqVO;
import cn.iocoder.yudao.module.asasc.controller.admin.salesreport.vo.SalesReportPageReqVO;
import cn.iocoder.yudao.module.asasc.dal.dataobject.salesreport.SalesReportDO;
import cn.iocoder.yudao.module.asasc.enums.DictTypeConstants;
import cn.iocoder.yudao.module.asasc.service.campaign.CampaignDataService;
import cn.iocoder.yudao.module.asasc.service.salesreport.SalesReportService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE;

/**
 * 广告数据和销售数据汇总报表，分组汇总查询（国家、日期、应用、广告系列）
 */
@Slf4j
@Component
public class AsaSummaryReportJob implements JobHandler {
    @Resource
    private CampaignDataService campaignDataService;
    @Resource
    private SalesReportService salesReportService;
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public String execute(String param) throws Exception {
        String msg;
        LocalDate strDate = null, endDate = null;
        Long orgId = null;
        if (param.contains("#")) {
            String[] params = param.split("#");
            if (params.length == 3) {
                strDate = LocalDate.parse(params[0]);
                endDate = LocalDate.parse(params[1]);
                orgId = Long.valueOf(params[2]);
            } else if (params.length == 2) {
                strDate = LocalDate.parse(params[0]);
                endDate = LocalDate.parse(params[1]);
            }
        } else {
            // 参数为空取前两天的日期
            strDate = LocalDateTimeUtils.getPassDay(-2).toLocalDate();
            endDate = LocalDateTimeUtils.getPassDay(-2).toLocalDate();
        }

        if (strDate == null || endDate == null) {
            msg = String.format("入参 %s 不对，结束汇总报表利润任务", strDate);
            log.error(msg);
            return msg;
        }

        LocalDate[] dates = {strDate, endDate};
        String orgName = DictFrameworkUtils.getDictDataLabel(DictTypeConstants.ASA_ORG_ID, String.valueOf(orgId));
        log.info("开始生成[{}]{}汇总报表利润...", orgName, dates);

        //1.查询销售数据
        SalesReportPageReqVO salesReportReqVO = new SalesReportPageReqVO();
        salesReportReqVO.setPageSize(PAGE_SIZE_NONE);
        salesReportReqVO.setBeginDate(dates);
        salesReportReqVO.setOrgId(orgId);
        PageResult<SalesReportDO> salesReportPageResult = salesReportService.getSalesReportPage(salesReportReqVO);
        List<SalesReportDO> salesReportList = salesReportPageResult.getList();

        if (salesReportList.isEmpty()) {
            msg = String.format("[%s]%s没有销售数据，汇总利润统计任务结束", orgName, Arrays.toString(dates));
            log.info(msg);
            return msg;
        }

        //把 salesReportList 中的 parentIdentifier 替换成 appleIdentifier
        salesReportList.forEach(a -> {
            if (!a.getParentIdentifier().trim().isBlank()) {
                a.setAppleIdentifier(DictFrameworkUtils.parseDictDataValue(DictTypeConstants.PKG_ID_APP_ID, a.getParentIdentifier()));
            }
        });
        log.info("[{}]{}salesReportList: {}", orgName, dates, salesReportList.size());

        // 分组汇总销售数据
        Map<String, Map<String, Object>> salesSummaryMap = salesReportList.stream().filter(data ->
                data.getParentIdentifier().trim().isBlank()).collect(Collectors.groupingBy(data ->
                data.getBeginDate() + "_" + data.getCountryCode() + "_" + data.getAppleIdentifier(),
                Collectors.collectingAndThen(Collectors.toList(), list -> {
            Map<String, Object> summary = new HashMap<>();
            summary.put("date", list.stream().map(SalesReportDO::getBeginDate).findFirst().orElse(null));
            summary.put("asaInstalls", list.stream().filter(d -> "1F".equals(d.getProductTypeIdentifier())).mapToInt(SalesReportDO::getUnits).sum());
            summary.put("asaReInstalls", list.stream().filter(d -> "3F".equals(d.getProductTypeIdentifier())).mapToInt(SalesReportDO::getUnits).sum());
            summary.put("asaUptInstalls", list.stream().filter(d -> "7F".equals(d.getProductTypeIdentifier())).mapToInt(SalesReportDO::getUnits).sum());
            summary.put("orgId", list.stream().map(SalesReportDO::getOrgId).filter(id -> !Objects.isNull(id)).findFirst().orElse(null));
            return summary;
        })));

        log.info("[{}]{}salesSummaryMap: {}", orgName, dates, salesSummaryMap);

        // 分组汇总订阅数据
        Map<String, Map<String, Object>> subSummaryMap = salesReportList.stream().filter(data -> !data.getParentIdentifier().trim().isBlank()).collect(Collectors.groupingBy(data -> data.getBeginDate() + "_" + data.getCountryCode() + "_" + data.getAppleIdentifier(), Collectors.collectingAndThen(Collectors.toList(), list -> {
            Map<String, Object> summary = new HashMap<>();
            summary.put("trialCount", list.stream().filter(d -> "New".equals(d.getSubscription())).mapToInt(SalesReportDO::getUnits).sum());
            summary.put("renewalCount", list.stream().filter(d -> "Renewal".equals(d.getSubscription()) && d.getUnits() > 0).mapToInt(SalesReportDO::getUnits).sum());
            summary.put("proceedsAmount", list.stream().filter(d -> "Renewal".equals(d.getSubscription()) && d.getUnits() > 0).map(SalesReportDO::getDeveloperProceedsUsd).reduce(BigDecimal.ZERO, BigDecimal::add));
            summary.put("salesAmount", list.stream().filter(d -> "Renewal".equals(d.getSubscription()) && d.getUnits() > 0).map(SalesReportDO::getCustomerPriceUsd).reduce(BigDecimal.ZERO, BigDecimal::add));
            summary.put("refundCount", list.stream().filter(d -> "Renewal".equals(d.getSubscription()) && d.getUnits() < 0).mapToInt(SalesReportDO::getUnits).sum());
            summary.put("refundSalesAmount", list.stream().filter(d -> "Renewal".equals(d.getSubscription()) && d.getUnits() < 0).map(SalesReportDO::getCustomerPriceUsd).reduce(BigDecimal.ZERO, BigDecimal::add));
            summary.put("refundProceedsAmount", list.stream().filter(d -> "Renewal".equals(d.getSubscription()) && d.getUnits() < 0).map(SalesReportDO::getDeveloperProceedsUsd).reduce(BigDecimal.ZERO, BigDecimal::add));
            return summary;
        })));
        log.info("[{}]{}subSummaryMap: {}", orgName, dates, subSummaryMap);

        //获取汇率配置表
        Map<Object, Object> rateMap = stringRedisTemplate.opsForHash().entries(AsaConst.rateKey);

        //3.构建 ProfitReportSaveReqVO 数据并入库
        List<CampaignDataSaveReqVO> reqVOList = new ArrayList<>();
        salesSummaryMap.forEach((key, value) -> {
            String[] keys = key.split("_");
            CampaignDataSaveReqVO saveReqVO = new CampaignDataSaveReqVO();
            saveReqVO.setAdamId(Long.parseLong(keys[2]));
            saveReqVO.setDate(LocalDate.parse(keys[0]));
            saveReqVO.setCountryOrRegion(keys[1]);
            saveReqVO.setAscInstalls(value.get("asaInstalls") != null ? (Integer) value.get("asaInstalls") : 0);
            saveReqVO.setAscReInstalls(value.get("asaReInstalls") != null ? (Integer) value.get("asaReInstalls") : 0);
            saveReqVO.setAscUptInstalls(value.get("asaUptInstalls") != null ? (Integer) value.get("asaUptInstalls") : 0);
            if (!Objects.isNull(value.get("orgId"))) {
                saveReqVO.setOrgId((Long) value.get("orgId"));
            }

            //订阅数据
            if (subSummaryMap.containsKey(key)) {
                saveReqVO.setAscTrial(subSummaryMap.get(key).get("trialCount") != null ? ((Number) subSummaryMap.get(key).get("trialCount")).intValue() : 0);
                saveReqVO.setAscRenewal(subSummaryMap.get(key).get("renewalCount") != null ? ((Number) subSummaryMap.get(key).get("renewalCount")).intValue() : 0);
                saveReqVO.setAscRefund(subSummaryMap.get(key).get("refundCount") != null ? ((Number) subSummaryMap.get(key).get("refundCount")).intValue() : 0);
                //金额都转成 CNY
                BigDecimal rate = rateMap.containsKey("CNY") ? new BigDecimal(rateMap.get("CNY").toString()) : BigDecimal.ONE;
                saveReqVO.setAscSales(subSummaryMap.get(key).get("salesAmount") != null ? ((BigDecimal) subSummaryMap.get(key).get("salesAmount")).multiply(rate) : BigDecimal.ZERO);
                saveReqVO.setAscProceeds(subSummaryMap.get(key).get("proceedsAmount") != null ? ((BigDecimal) subSummaryMap.get(key).get("proceedsAmount")).multiply(rate) : BigDecimal.ZERO);
                saveReqVO.setAscRefundSales(subSummaryMap.get(key).get("refundSalesAmount") != null ? ((BigDecimal) subSummaryMap.get(key).get("refundSalesAmount")).multiply(rate) : BigDecimal.ZERO);
                saveReqVO.setAscRefundProceeds(subSummaryMap.get(key).get("refundProceedsAmount") != null ? ((BigDecimal) subSummaryMap.get(key).get("refundProceedsAmount")).multiply(rate) : BigDecimal.ZERO);
            }
            reqVOList.add(saveReqVO);
        });

        //汇总更新和插入的数据
        Integer insertCount = 0, updateCount = 0;
        for (CampaignDataSaveReqVO reqVOList2 : reqVOList) {
            Map<String, Integer> result = campaignDataService.updateOrSaveCampaignDataByKey(reqVOList2);
            insertCount += result.get("insertCount");
            updateCount += result.get("updateCount");
        }
        msg = String.format("[%s]%s 汇总利润生成报表数据 %s 条，插入 %s 条，更新 %s 条", orgName, Arrays.toString(dates),
                reqVOList.size(), insertCount, updateCount);
        log.info(msg);
        return msg;
    }
}